package nodex

import (
	"context"
	"gitee.com/zhongguo168a/go-nodex/nodex/chanrpc"
	"gitee.com/zhongguo168a/go-nodex/nodex/gocall"
	"gitee.com/zhongguo168a/gocodes/datax"
	"gitee.com/zhongguo168a/gocodes/myx/cachex"
	"gitee.com/zhongguo168a/gocodes/myx/errorx"
	"gitee.com/zhongguo168a/gocodes/myx/logx"
)

// IChanRPC chanrpc为内部以go为单位的 rpc服务器
type IChanRPC interface {
	Ident() string
	Open() *chanrpc.Client
	Server() *chanrpc.Server
	Stop()
	Cache() *cachex.Cache
	Contains(msgId string) bool
	// 只通知rpc，不会返回数据
	Notify(msgId string, ctx context.Context, args interface{})
	//调佣rpc的方法，并返回错误信息
	Call0(msgId string, ctx context.Context, args interface{}) (err error)
	//调佣rpc的方法，并返回数据和错误信息
	Call1(msgId string, ctx context.Context, args interface{}, replay interface{}) (err error)
}

func newRPC(name, ident string, config ChanRPCSelector) (obj *ChanRPC) {
	obj = &ChanRPC{}
	obj.name = name
	obj.ident = ident
	obj.selector = config
	if obj.selector == nil {
		// 默认的选择器
		obj.selector = defaultGetRPCHandle
	}
	obj.server = chanrpc.NewServer(0)
	obj.closeSig = make(chan bool, 0)
	obj.g = gocall.New(1)
	return
}

type ChanRPC struct {
	server   *chanrpc.Server
	g        *gocall.Go
	closeSig chan bool
	cache    *cachex.Cache
	onRuns   []func() (err error)
	// 配置，无指针，避免静态
	selector ChanRPCSelector
	//
	ident string
	name  string
}

func (s *ChanRPC) Contains(msgId string) bool {
	return s.server.Contains(msgId)
}

func (s *ChanRPC) Ident() string {
	return s.ident
}

func (s *ChanRPC) Cache() *cachex.Cache {
	return s.cache
}

func (s *ChanRPC) Open() *chanrpc.Client {
	return s.server.Open(0)
}
func (s *ChanRPC) Notify(msgId string, ctx context.Context, args interface{}) {
	if !s.Contains(msgId) {
		logx.Error(errorx.New("nodex chanrpc msg not found", datax.M{"msgId": msgId}))
		return
	}
	err := s.Open().Call0(msgId, ctx, args)
	if err != nil {
		logx.Error(errorx.New("nodex chanrpc call0", datax.M{"msgId": msgId}))
		return
	}
	return
}
func (s *ChanRPC) Call0(msgId string, ctx context.Context, args interface{}) error {
	if !s.Contains(msgId) {
		logx.Error(errorx.New("nodex chanrpc msg not found", datax.M{"msgId": msgId}))
		return nil
	}
	results, err := s.Open().Call1(msgId, ctx, args)
	if err != nil {
		logx.Error(errorx.New("nodex chanrpc call1", datax.M{"msgId": msgId}))
		return nil
	}
	if results != nil {
		return results.(error)
	}

	return nil
}

func (s *ChanRPC) Call1(msgId string, ctx context.Context, args interface{}, replay interface{}) (err error) {
	if !s.Contains(msgId) {
		logx.Error(errorx.New("nodex chanrpc msg not found", datax.M{"msgId": msgId}))
		return nil
	}
	results, err := s.Open().Call1(msgId, ctx, args, replay)
	if err != nil {
		logx.Error(errorx.New("nodex chanrpc call1", datax.M{"msgId": msgId}))
		return nil
	}
	if results != nil {
		return results.(error)
	}

	return nil
}

func (s *ChanRPC) Server() *chanrpc.Server {
	return s.server
}

func (s *ChanRPC) G() *gocall.Go {
	return s.g
}

func (s *ChanRPC) Run() {

	for _, val := range s.onRuns {
		err := val()
		if err != nil {
			panic(err)
		}
	}

	for {
		select {
		case <-s.closeSig:
			s.server.Close()
			close(s.closeSig)
			return
		case ci := <-s.server.ChanCall:
			err := s.server.Exec(ci)
			if err != nil {
				logx.Error(err)
			}
		case cb := <-s.G().ChanCb:
			s.G().Cb(cb)
		}
	}
	//
}

func (s *ChanRPC) Stop() {
	s.closeSig <- true
}
